home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 4 / Info_Mac IV CD-ROM (Pacific HiTech Inc.)(August 1994).iso / Development / Source / DBL Pascal Library / INIT Shell Folder / INIT Shell ƒ / Shell ƒ / INITShellInlines.p < prev    next >
Text File  |  1990-05-28  |  10KB  |  258 lines

  1. unit INITShellInlines;
  2. {Copyright © 1990, David B. Lamkins}
  3. {All rights reserved.}
  4.  
  5. interface
  6.  
  7. {•• This unit contains inline routines which depend upon very particular conventions}
  8. {•• for their proper use.  Many of these routines modify the runtime stack in a way}
  9. {•• which will cause system crashes if not used according to their directions.  Please}
  10. {•• read the comments and accompanying documentation carefully before use…}
  11.  
  12. {Patches:}
  13. {}
  14. {Register parameters may be accessed and register values returned using the inline functions}
  15. {provided in this unit.  The ability to return register values depends upon THINK Pascal}
  16. {generating a simple UNLK, RTS epilog for procedures.}
  17. {}
  18. {Stack parameters are accessed parasitically by offset, and must never be declared.  The}
  19. {ability to access stack parameters depends upon THINK Pascal always generating a LINK}
  20. {prologue for procedures.}
  21. {}
  22. {Rather than returning to its caller, the patch code may transfer control to a patched routine}
  23. {by using the SetTrapExit inline procedure declared in this unit.  This is the normal and preferred}
  24. {method of handling a trap patch.  The alternative requires you to call the patched routine from}
  25. {within this patch code using the inline CallPatchedTrap procedure, and results in a "tail patch".}
  26. {}
  27. {VBLs:}
  28. {}
  29. {VBLs do not have parameters.  On entry, A0 points to the VBL's own VBLTask record.  You can}
  30. {use GetVBLTask to copy this pointer to a local variable.  Your VBL must set its count to a nonzero}
  31. {value if it is to be requeued.  See II-349 and TN 180 for further details.}
  32.  
  33.     uses
  34.         INITShellGlobals, Retrace;
  35.  
  36. {This procedure must be called at most once, and must be called from the main routine, not}
  37. {from a nested routine.  It modifies the return address on the stack to transfer control via}
  38. {a jump to the stashed address of the patch code, rather than returning to the caller.  Control}
  39. {will eventually pass back to the caller when the patched trap returns.  Call this procedure}
  40. {just before exit, as late as possible, and *never* more than once!  The globals access}
  41. {routines (GlobalsHandle, LockGlobals, UnlockGlobals) depend on this not having been called.}
  42.     procedure SetTrapExit;
  43.     inline
  44.         $54AE, $0004;    {ADDQ.L #2,4(A6)}
  45.  
  46. {This procedure must be called from the main routine, not from a nested routine.  It calls}
  47. {the patched trap via its stashed address.  Note that it preserves all registers.}
  48.     procedure CallPatchedTrap;
  49.     inline
  50.         $42A7,            {CLR.L -(SP)                -- make room for return address}
  51.         $42A7,            {CLR.L -(SP)                -- make room for call address}
  52.         $2F08,            {MOVE.L A0,-(SP)        -- save A0}
  53.         $41FA, $0012,    {LEA $14(PC),A0            -- calculate call return address}
  54.         $2F48, $0008,    {MOVE.L A0,8(SP)        -- stuff return address into stack}
  55.         $206E, $0004,    {MOVEA.L 4(A6),A0        -- get header return}
  56.         $2068, $0004,    {MOVEA.L 4(A0),A0        -- fetch address of trapped patch}
  57.         $2F48, $0004,    {MOVE.L A0,4(SP)        -- tuck into stack}
  58.         $205F,            {MOVEA.L (SP)+,A0        -- restore A0}
  59.         $4E75;            {RTS                        -- make the call}
  60.  
  61. {This procedure must be called from the main routine, not from a nested routine.  It deallocates}
  62. {the local stack frame, discards the specified number of bytes of parameters, and returns to}
  63. {the patched trap's caller.  This is needed if you want to completely replace the functionality of}
  64. {the original trap with your own code.  The only use I can think of for this is in virus protection}
  65. {software that wants to selectively suppress the action of certain traps.  Be certain that you}
  66. {pass an even value as the parameter - an odd value will misalign the stack and cause a double}
  67. {fault at runtime.}
  68.     procedure DeallocateAndReturn (paramSize: INTEGER);
  69.     inline
  70.         $206E, $0008,    {MOVEA.L 8(A6),A0    -- save original return address}
  71.         $301F,            {MOVE.W (SP)+,D0    -- get param byte size}
  72.         $4E5E,            {UNLK A6                -- discard frame}
  73.         $4FF7, $0008,    {LEA 8(SP,D0.W),SP    -- discard header & caller RA, and params}
  74.         $4ED0;            {JMP (A0)            -- return}
  75.  
  76. {The following functions are used to access parameters passed in registers.  In order to capture}
  77. {registers passed to a trap, the GetReg__ functions must be called first thing in the patch code,}
  78. {and may only appear in a statement which assigns the value to a local variable of main.}
  79. {This works because the THINK Pascal compiler is good enough not to shuffle values through}
  80. {registers to do an assignment.  The actual code generated looks something like this:}
  81. {    A0 := RegA0;                    -- the Pascal source}
  82. {    ADDQ.L    #4,A7                -- the compiler reserves space for the result}
  83. {    MOVE.L    A0,(A7)            -- the inline code expansion of function RegA0}
  84. {    MOVE.L    (A7)+,-__(A6)    -- the assignment to a local variable}
  85.     function GetRegA0: LONGINT;
  86.     inline
  87.         $2E88;    {MOVE.L A0,(A7)}
  88.  
  89.     type
  90.         VBLTaskPtr = ^VBLTask;
  91.  
  92.     function GetVBLTask: VBLTaskPtr;    {an alias for RegA0, to be used in VBLs}
  93.     inline
  94.         $2E88;    {MOVE.L A0,(A7)}
  95.  
  96.     function GetRegA1: LONGINT;
  97.     inline
  98.         $2E89;    {MOVE.L A1,(A7)}
  99.  
  100.     function GetRegD0: LONGINT;
  101.     inline
  102.         $2E80;    {MOVE.L D0,(A7)}
  103.  
  104.     function GetRegD1: LONGINT;
  105.     inline
  106.         $2E81;    {MOVE.L D1,(A7)}
  107.  
  108.     function GetRegD2: LONGINT;
  109.     inline
  110.         $2E82;    {MOVE.L D2,(A7)}
  111.  
  112. {The following procedures are used to pass register parameters to a patched trap.  These}
  113. {calls should immediately preceed ExitToTrap or a call to CallPatchedTrap.  As noted above,}
  114. {the THINK Pascal compiler is good enough not to shuffle values through registers, so the}
  115. {order of these calls doesn't matter.}
  116.     procedure SetRegA0 (value: LONGINT);
  117.     inline
  118.         $205F;    {MOVEA.L (A7)+,A0}
  119.  
  120.     procedure SetRegA1 (value: LONGINT);
  121.     inline
  122.         $225F;    {MOVEA.L (A7)+,A1)}
  123.  
  124.     procedure SetRegD0 (value: LONGINT);
  125.     inline
  126.         $201F;    {MOVE.L (A7)+,D0}
  127.  
  128.     procedure SetRegD1 (value: LONGINT);
  129.     inline
  130.         $221F;    {MOVE.L (A7)+,D1}
  131.  
  132.     procedure SetRegD2 (value: LONGINT);
  133.     inline
  134.         $241F;    {MOVE.L (A7)+,D2}
  135.  
  136. {The following functions access parameters parasitically.  You need to know the size of}
  137. {each parameter on the stack.  The offset you will pass to the following routines is the}
  138. {sum of the stack size of all the parameters which follow it in the parameter list.  For}
  139. {example, if you are patching the stack trap:}
  140. {    AddResource(h: Handle; rType: ResType; id: INTEGER; name: STR255);}
  141. {you'll use the following expressions to access the parameters of the caller:}
  142. {    h := Handle(LParam(10));}
  143. {    rType := ResType(LParam(6));}
  144. {    id := WParam(4);}
  145. {    namePtr := StringPtr(LParam(0));}
  146. {}
  147. {These procedures depend upon the stack protocol which is determined by the header code.}
  148. {When these procedures are called, the stack will contain (starting "deep" in the stack) the}
  149. {trap's parameters in left-to-right order, the caller's return address, the header's return}
  150. {address, the frame pointer, and any local variables of the patch code.}
  151. {}
  152. {There is one function for each size of parameter which may be pushed: LParam for 4-byte}
  153. {parameters, WParam for 2-bytes, and BParam for 1-byte parameters.  The results will}
  154. {usually have to be typecast.}
  155. {}
  156. {Don't try to be clever and put the parameters in the declaration of main.  Remember that the}
  157. {header code will mess with the stack before your main gets control, and since the standard}
  158. {epilogue code may be subverted by the SetTrapExit procedure, your declaration may break}
  159. {even if you account for the return address as an extra parameter.}
  160.     function LParam (offset: INTEGER): LONGINT;
  161.     inline
  162.         $301F,            {MOVE.W (A7)+,D0}
  163.         $2EB6, $000C;    {MOVE.L 12(A6,D0.W),(A7)}
  164.  
  165.     function WParam (offset: INTEGER): INTEGER;
  166.     inline
  167.         $301F,            {MOVE.W (A7)+,D0}
  168.         $3EB6, $000C;    {MOVE.W 12(A6,D0.W),(A7)}
  169.  
  170.     function BParam (offset: INTEGER): Byte;
  171.     inline
  172.         $301F,            {MOVE.W (A7)+,D0}
  173.         $1EB6, $000C;    {MOVE.B 12(A6,D0.W),(A7)}
  174.  
  175. {The following procedures stuff a result into the stack.  The comments for the parameter}
  176. {access routines, above, apply here as well.}
  177.     procedure LResult (value: LONGINT; offset: INTEGER);
  178.     inline
  179.         $301F,            {MOVE.W (A7)+,D0}
  180.         $2D9F, $000C;    {MOVE.L (A7)+,12(A6,D0.W)}
  181.  
  182.     procedure WResult (value, offset: INTEGER);
  183.     inline
  184.         $301F,            {MOVE.W (A7)+,D0}
  185.         $3D9F, $000C;    {MOVE.W (A7)+,12(A6,D0.W)}
  186.  
  187.     procedure BResult (value: Byte; offset: INTEGER);
  188.     inline
  189.         $301F,            {MOVE.W (A7)+,D0}
  190.         $1D9F, $000C;    {MOVE.B (A7)+,12(A6,D0.W)}
  191.  
  192. {The following procedures are used to push stack arguments prior to tail-calling a}
  193. {patched stack-based trap.  The compiler actually generates the push, the NOP is}
  194. {a placeholder because the compiler expects something after an inline declaration.}
  195.     procedure PushL (value: LONGINT);
  196.     inline
  197.         $4e71;    {NOP}
  198.  
  199.     procedure PushW (value: INTEGER);
  200.     inline
  201.         $4e71;    {NOP}
  202.  
  203.     procedure PushB (value: Byte);
  204.     inline
  205.         $4e71;    {NOP}
  206.  
  207. {The following functions are used to pop a result from the stack after tail-calling a}
  208. {patched stack-based trap.  As above, the NOP is only a placeholder.}
  209.     function PopL: LONGINT;
  210.     inline
  211.         $4E71;    {NOP}
  212.  
  213.     function PopW: INTEGER;
  214.     inline
  215.         $4E71;    {NOP}
  216.  
  217.     function PopB: Byte;
  218.     inline
  219.         $4E71;    {NOP}
  220.  
  221. {The following function fetches the handle to the INIT globals.  This must be called from}
  222. {the main program, since it relies on finding a return address into the code header at 4(A6).}
  223.     function GlobalsHandle: INITGlobalsHandle;
  224.     inline
  225.         $206E, $0004,    {MOVEA.L 4(A6),A0        -- get the address of the return to the header}
  226.         $2EA8, $000A;    {MOVE.L 10(A0),(A7)    -- fetch the globals handle}
  227.  
  228. {The following procedures are used to lock and unlock the globals handle.  They keep the}
  229. {globals handle locked until UnlockGlobals calls balance LockGlobals calls.  These must be}
  230. {called from the main program, since they rely on finding a return address into the code}
  231. { header at 4(A6).}
  232.     procedure LockGlobals;
  233.     inline
  234.         $206E, $0004,    {MOVEA.L 4(A6),A0        -- get the address of the return to the header}
  235.         $5268, $0008,    {ADDQ.W #1,8(A0)        -- bump the lock counter up by one}
  236.         $2068, $000A,    {MOVEA.L 10(A0),A0    -- fetch the globals handle}
  237.         $A029;            {_HLock                    -- lock it}
  238.  
  239.     procedure UnlockGlobals;
  240.     inline
  241.         $206E, $0004,    {MOVEA.L 4(A6),A0        -- get the address of the return to the header}
  242.         $5368, $0008,    {SUBQ.W #1,8(A0)        -- bump the lock counter down by one}
  243.         $6606,            {BNE.S *+8                -- unless unlocks balance locks, skip out}
  244.         $2068, $000A,    {MOVEA.L 10(A0),A0    -- fetch the globals handle}
  245.         $A02A;            {_HUnlock                    -- really unlock it}
  246.  
  247. {Finally, because I don't always get it right the first time…}
  248.     procedure Break;
  249.     inline
  250. {$IFC Debugging}
  251.         $A9FF;    {_Debugger}
  252. {$ELSEC}
  253.         $4E71;    {NOP}
  254. {$ENDC}
  255.  
  256. implementation
  257.     {It's all in the interface…}
  258. end.